package com.imooc.seckill.service;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import com.imooc.commons.constant.ApiConstant;
import com.imooc.commons.constant.RedisKeyConstant;
import com.imooc.commons.model.domain.ResultInfo;
import com.imooc.commons.model.pojo.SeckillVouchers;
import com.imooc.commons.model.pojo.VoucherOrders;
import com.imooc.commons.model.vo.SignInDinerInfo;
import com.imooc.commons.utils.AssertUtil;
import com.imooc.commons.utils.ResultInfoUtil;
import com.imooc.seckill.mapper.SeckillVouchersMapper;
import com.imooc.seckill.mapper.VoucherOrderMapper;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;

/**
 * \* @author: bear
 * \* Date: 2021-07-30-15:23
 * \* describe:
 */
@Service
public class SeckillTwoService {

	@Resource
	private SeckillVouchersMapper seckillVouchersMapper;
	@Resource
	private VoucherOrderMapper voucherOrderMapper;

	@Value("${service.name.ms-oauth-server}")
	private String oauthServerName;

	@Resource
	private RestTemplate restTemplate;
	@Resource
	private RedisTemplate redisTemplate;
	/**
	 * 添加需要抢购的代金券
	 *
	 * @param seckillVouchers
	 */
	@Transactional(rollbackFor = Exception.class)
	public void addSeckillVouchers(SeckillVouchers seckillVouchers){
		//非空校验
		AssertUtil.isTrue(seckillVouchers.getFkVoucherId() == null,"请选择需要抢购的代金卷");
		AssertUtil.isTrue(seckillVouchers.getAmount() == 0,"请输入抢购总数量");
		Date now = new Date();
		AssertUtil.isNotNull(seckillVouchers.getStartTime(),"请输入开始时间");
		//生产环境下放行，这里是方便测试
		AssertUtil.isNotNull(seckillVouchers.getEndTime(),"请输入结束时间");
		AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()),"结束时间不能早于开始时间");
		AssertUtil.isTrue(seckillVouchers.getStartTime().after(seckillVouchers.getEndTime()),"开始时间不能晚于结束时间");


		// 验证数据库中是否已经存在该券的秒杀活动
		SeckillVouchers seckillFormDB = seckillVouchersMapper.selectVoucher(seckillVouchers.getFkVoucherId());
		AssertUtil.isTrue(seckillFormDB !=null ,"改卷已经有了抢购活动");
		// 插入数据库
		seckillVouchersMapper.save(seckillVouchers);

	}

	public ResultInfo doSeckill(Integer voucherId,String accessToken,String path){
		//基本参数校验
		AssertUtil.isTrue(voucherId == null || voucherId<0,"请选择要抢购的代金卷");
		AssertUtil.isNotEmpty(accessToken,"请登录");

		//判断此代金卷是否加入抢购
		SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId);
		AssertUtil.isTrue(seckillVouchers == null ,"该代金券并未有抢购活动");

		// 判断是否有效
		AssertUtil.isTrue(seckillVouchers.getIsValid() == 0, "该活动已结束");
		// 判断是否开始、结束
		Date now = new Date();
		AssertUtil.isTrue(now.before(seckillVouchers.getStartTime()), "该抢购还未开始");
		AssertUtil.isTrue(now.after(seckillVouchers.getEndTime()), "该抢购已结束");
		// 判断是否卖完
		AssertUtil.isTrue(seckillVouchers.getAmount() < 1, "该券已经卖完了");

		//获取用户信息
		String url = oauthServerName + "/user/me?access_token={accessToken}";

		ResultInfo resultInfo = restTemplate.getForObject(url, ResultInfo.class, accessToken);
		if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {
			resultInfo.setPath(path);
			return resultInfo;
		}
		//这里的data是个linkedHashmap SignInDinerInfo
		SignInDinerInfo dinerInfo = BeanUtil
				.fillBeanWithMap((LinkedHashMap)resultInfo.getData(),new SignInDinerInfo(),false);

		// 判断登录用户是否已抢到(一个用户针对这次活动只能买一次)
		VoucherOrders orders = voucherOrderMapper.findDinerOrder(dinerInfo.getId(),seckillVouchers.getId());

		AssertUtil.isTrue(orders !=null,"改用户已经抢到代金卷，无需再抢");

		//-------注释掉原先走关系型数据库的流程----------------
		//扣库存
		int count = seckillVouchersMapper.stockDecrease(seckillVouchers.getId());
		AssertUtil.isTrue(count == 0, "该券已经卖完了");

		// 下单
		VoucherOrders voucherOrders = new VoucherOrders();
		voucherOrders.setFkDinerId(dinerInfo.getId());
		// Redis 中不需要维护外键信息
		//voucherOrders.setFkSeckillId(seckillVouchers.getId());
		voucherOrders.setFkVoucherId(seckillVouchers.getFkVoucherId());
		String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
		voucherOrders.setOrderNo(orderNo);
		voucherOrders.setOrderType(1);
		voucherOrders.setStatus(0);
		count = voucherOrderMapper.save(voucherOrders);
		AssertUtil.isTrue(count == 0, "用户抢购失败");

		return ResultInfoUtil.buildSuccess(path, "抢购成功");
	}
}
